﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;

using AdaptationProject.Properties;
using AdaptationProject.Utils;
using SharedTypes;
using AdaptationProject.Forms;

namespace AdaptationProject
{
    // Главная форма
    public partial class MainForm : Form
    {
        private const string XmlExt = ".xml";
        private const string DllExt = ".dll";

        private static IAdoptationMethod adoMethod;
        private static IAlgorithm currentCompression;
        private static ReportInformationContainer reportInfo;

        private int cmbMethodSelectedIndex = 0;

        public MainForm()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
            reportInfo = new ReportInformationContainer();

            btnStart.Enabled = false;
            // testing
            tbFolderPath.Text = @"C:\FolderTesting";
        }

        public static void ShowMsg(string txt)
        {
            MessageBox.Show(txt);
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            AssemblyLoader.StartupChecker();
            LoadUniversalAlgorithms();
            LoadMethods();
            InitSetupMethodParameters();
        }

        private void btnAddFile_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                tbFolderPath.Text = string.Empty;
                tbFolderPath.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        private void LoadMethods()
        {
            ResContainer.ClearMethods();
            AssemblyLoader.LoadMethods();
        }

        // Загрузка универсальных алгоритмов анализа
        private void LoadUniversalAlgorithms()
        {
            // очистка контейнер алгоритмов от старого значения
            ResContainer.ClearAlgorithmsUniversal();
            AssemblyLoader.LoadAlgorithms(new XMLParamParser());
            // получить каждый алгоритм
            foreach (KeyValuePair<string, IAlgorithm> algorithm in ResContainer.GetAllUniversalAlgorithms())
            {
                // и добавить его в контейнер
                cmbAlgorithms.Items.Add(algorithm.Value.AlgorithmName);
            }
        }

        private void btnRefreshMethods_Click(object sender, EventArgs e)
        {
            LoadMethods();
        }

        private void выходToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        // Выполнить подбор параметров
        private void выполнитьАнализToolStripMenuItem_Click(object sender, EventArgs e)
        {
            reportInfo.Clear();
            if (tbFolderPath.Text == string.Empty ||
               (cmbAlgorithms.SelectedIndex == -1))
            {
                MessageBox.Show(Resources.MAIN_NotAllSelectedText, Resources.MAIN_NotAllSelectedTitle,
                                MessageBoxButtons.OK);
            }
            else
            {
                ResContainer.GetUniversalAlgorithm(cmbAlgorithms.SelectedIndex, out currentCompression);

                // получить метод исполнительного файла
                // получить алгоритм исполнительного файла
                if (ResContainer.GetMethod(cmbMethodSelectedIndex, out adoMethod) &&
                    null != currentCompression)
                {
                    // установить параметры отчета
                    if (SetReportParams() == false)
                        return;
                    adoMethod.ProgressEventHandler += ProgressEventHandler;
                    //currentCompression.SetCompressionTarget(tbFolderPath.Text);
                    // установить параметры подбора
                    adoMethod.SetParameters(ResContainer.GetMethodCustomParameters(cmbMethodSelectedIndex));
                    AnalisysWithStateObject obj = new AnalisysWithStateObject(adoMethod, currentCompression, ref reportInfo);
                    obj.OnProcessDone += OnProcessDoneEventHandler;
                    // установить количество экспириментов
                    obj.SetNumberofExperiments((double)this.experimentCount.Value);
                    Thread thread = new Thread(obj.RunAdoptation);
                    // начать анализ
                    ShowAdditional();
                    thread.Start();
                }
                else
                {
                    MessageBox.Show(Resources.MAIN_ErrorStartingAdoptationText,
                                    Resources.MAIN_ErrorStartingAdoptationTitle,
                                    MessageBoxButtons.OK);
                }
            }
        }

        // Сжимать файлы
        void DoCompressAlgorithm(bool isDivFile, out AnalisysWithStateObject obj)
        {
            ResContainer.GetAlgorithm(cmbAlgorithms.SelectedIndex, out currentCompression);

            // получить метод исполнительного файла
            // получить алгоритм исполнительного файла
            if (ResContainer.GetMethod(cmbMethodSelectedIndex, out adoMethod) &&
                null != currentCompression)
            {
                // установить параметры отчета
                if (SetReportParams() == false)
                {
                    obj = null;
                    return;
                }
                adoMethod.ProgressEventHandler += ProgressEventHandler;
                currentCompression.SetCompressionTarget(tbFolderPath.Text);
                // установить параметры подбора
                adoMethod.SetParameters(ResContainer.GetMethodCustomParameters(cmbMethodSelectedIndex));
                obj = new AnalisysWithStateObject(adoMethod, currentCompression, ref reportInfo);
                obj.OnProcessDone += OnProcessDoneEventHandler;
                // установить количество экспириментов
                obj.SetNumberofExperiments((double)this.experimentCount.Value);
                // начать анализ
                ShowAdditional();
                if (isDivFile)
                {
                    obj.RunDevFileAdoptation();
                }
                else
                {
                    obj.RunAdoptation();
                }
            }
            else
            {
                obj = null;
                MessageBox.Show(Resources.MAIN_ErrorStartingAdoptationText,
                                Resources.MAIN_ErrorStartingAdoptationTitle,
                                MessageBoxButtons.OK);
            }
        }

        // Выполнить подбор параметров
        private void выполнитьСравнениеToolStripMenuItem_Click(object sender, EventArgs e)
        {
            reportInfo.Clear();
            if (tbFolderPath.Text == string.Empty || cmbMethodSelectedIndex == -1 ||
               (cmbAlgorithms.SelectedIndex == -1))
            {
                MessageBox.Show(Resources.MAIN_NotAllSelectedText, Resources.MAIN_NotAllSelectedTitle,
                                MessageBoxButtons.OK);
            }
            else
            {
                ResContainer.GetUniversalAlgorithm(cmbAlgorithms.SelectedIndex, out currentCompression);

                // получить метод исполнительного файла
                // получить алгоритм исполнительного файла
                if (ResContainer.GetMethod(cmbMethodSelectedIndex, out adoMethod) &&
                    null != currentCompression)
                {
                    // установить параметры отчета
                    if (SetReportParams() == false)
                        return;
                    adoMethod.ProgressEventHandler += ProgressEventHandler;
                    //currentCompression.SetCompressionTarget(tbFolderPath.Text);
                    // установить параметры подбора
                    adoMethod.SetParameters(ResContainer.GetMethodCustomParameters(cmbMethodSelectedIndex));
                    AnalisysWithStateObject obj = new AnalisysWithStateObject(adoMethod, currentCompression, ref reportInfo);
                    obj.OnProcessDone += OnProcessDoneEventHandler;
                    // установить количество экспириментов
                    obj.SetNumberofExperiments((double)this.experimentCount.Value);
                    Thread thread = new Thread(obj.RunAdoptation);
                    // начать анализ
                    ShowAdditional();
                    thread.Start();
                }
                else
                {
                    MessageBox.Show(Resources.MAIN_ErrorStartingAdoptationText,
                                    Resources.MAIN_ErrorStartingAdoptationTitle,
                                    MessageBoxButtons.OK);
                }
            }
        }

        private void btnClearFileList_Click(object sender, EventArgs e)
        {
            выполнитьАнализToolStripMenuItem_Click(sender, e);
        }

        private void импортироватьМетодИсполнительногоФайлаToolStripMenuItem_Click(object sender, EventArgs e) // это метод анализа а не исполнительного файла
        {
            using (OpenFileDialog dlg = new OpenFileDialog())
            {
                dlg.CheckFileExists = true;
                dlg.CheckPathExists = true;
                dlg.ValidateNames = true;
                dlg.DefaultExt = DllExt;
                dlg.Filter = "XML files (*" + DllExt + ")|*" + DllExt;
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    if (dlg.SafeFileName.EndsWith(DllExt))
                    {
                        try
                        {
                            File.Copy(dlg.FileName, Path.Combine(MySettings.MethodsCachePath, dlg.SafeFileName), false);
                            LoadMethods();
                        }
                        catch (IOException exception)
                        {
                            MessageBox.Show(exception.Message);
                        }
                    }
                    else
                    {
                        MessageBox.Show(Resources.MAIN_InvalidFileExtText, Resources.MAIN_InvalidFileExtTitle,
                                        MessageBoxButtons.OK);
                    }
                }
            }
        }

        // Прогресс бар
        private void ProgressEventHandler(object sender, ProgressEventArgs args)
        {
            try
            {
                pbAdoptationProgress.Value += args.currentProgress;
                lbCurrentProgress.Text = string.Format("Текущий прогресс: {0}%", pbAdoptationProgress.Value/10000);
            }
            catch (Exception e)
            {
                
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private void OnProcessDoneEventHandler(object sender, AdoptationDonEventArgs eventArgs)
        {
            IDictionary<int, LinkedParameter> bestArgs = eventArgs.bestParameters; // TODO: do something with finded parameters
            HideAdditional();
        }

        private void ShowAdditional()
        {
            pbAdoptationProgress.Value = 0;
            lbCurrentProgress.Text = "   Инициализация...";
            btnStart.Enabled = false;
            lbCurrentProgress.Visible = true;
        }

        private void HideAdditional()
        {
            adoMethod.ProgressEventHandler -= ProgressEventHandler;
            btnStart.Enabled = true;
            lbCurrentProgress.Text = "Текущий прогресс: 100%";
        }

        // Вывод параметров метода
        private void btnShowSettings_Click(object sender, EventArgs e)
        {
            // получить выбранный метод
            SetupMethodParameters.MethodID = cmbMethodSelectedIndex;
            // создать форму для вывода параметор
            var form = new SetupMethodParameters(tabControlDefault.TabPages[1]);
            // показать парамтры
            form.Show();
        }

        /// <summary>
        /// Установить пармаметры
        /// </summary>
        private bool SetReportParams()
        {
            reportInfo.AlgorithmName = currentCompression.AlgorithmName;
            reportInfo.LaunchDate = DateTime.Now;
            DirectoryInfo tmp = new DirectoryInfo(tbFolderPath.Text);
            reportInfo.FileNames = GetAllFiles(tmp);
            return reportInfo.FileNames != null;
        }

        // Получить все файлы директории
        private FileInfo[] GetAllFiles(DirectoryInfo dir)
        {
            try
            {
                DirectoryInfo[] dirs = dir.GetDirectories();
                FileInfo[] ff = dir.GetFiles();
                if (dirs.Length != 0)
                {
                    foreach (DirectoryInfo newDir in dirs)
                    {
                        int oldSize = ff.Length;
                        FileInfo[] tmp = GetAllFiles(newDir);
                        Array.Resize(ref ff, tmp.Length + oldSize);
                        Array.Copy(tmp, 0, ff, oldSize, tmp.Length);
                    }
                }
                if (ff.Length == 0)
                {
                    MessageBox.Show("Файлы отсутствуют в: " + dir.Name,
                                "Ошибка",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Warning);
                    return null;
                }
                return ff;
            }
            catch (DirectoryNotFoundException ex)
            {
                MessageBox.Show("Ошибка задания параметров: " + ex.Message,
                                "Ошибка в содержимом файла",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                return null;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + ": " + dir.Name,
                                "Ошибка",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                return null;
            }

        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Reports repoForm = new Reports();
            repoForm.Show();
        }

        private void toolStripMenuItemCmdParams_Click(object sender, EventArgs e)
        {
            CmdParams cmdForm = new CmdParams();

            if (tbFolderPath.Text != string.Empty &&
               (cmbAlgorithms.SelectedIndex != -1))
            {
                IAlgorithm current;
                ResContainer.GetUniversalAlgorithm(cmbAlgorithms.SelectedIndex, out current);
                cmdForm.LoadInfo(current.FullPathXml);
            }
            
            DialogResult result = cmdForm.ShowDialog();
        }

        private void btnRefreshUniversalAlgorithms_Click(object sender, EventArgs e)
        {
            LoadUniversalAlgorithms();
        }

        private void buttonCompare_Click(object sender, EventArgs e)
        {
            AnalisysWithStateObject obj1;
            DoCompressAlgorithm(true, out obj1);
        }

        void ChangeStateBtnStart()
        {
            if (-1 != cmbAlgorithms.SelectedIndex)
            {
                btnStart.Enabled = true;
            }
        }

        private void cmbUniversalAlgorithms_SelectionChangeCommitted(object sender, EventArgs e)
        {
            ChangeStateBtnStart();
        }

        private void cmbAlgorithms_SelectionChangeCommitted(object sender, EventArgs e)
        {
            ChangeStateBtnStart();
        }

        private void cmbMethod_SelectionChangeCommitted(object sender, EventArgs e)
        {
            ChangeStateBtnStart();
        }

        void InitSetupMethodParameters()
        {
            // получить выбранный метод
            SetupMethodParameters.MethodID = cmbMethodSelectedIndex;
            // создать форму для вывода параметор
            var form = new SetupMethodParameters(tabControlDefault.TabPages[1]);
        }

        private void button13_Click(object sender, EventArgs e)
        {
            ResContainer.GetUniversalAlgorithm(cmbAlgorithms.SelectedIndex, out currentCompression);

            // получить метод исполнительного файла
            // получить алгоритм исполнительного файла
            if (ResContainer.GetMethod(cmbMethodSelectedIndex, out adoMethod) &&
                null != currentCompression)
            {
                // установить параметры отчета
                if (SetReportParams() == false)
                    return;
                adoMethod.ProgressEventHandler += ProgressEventHandler;
                //currentCompression.SetCompressionTarget(tbFolderPath.Text);
                // установить параметры подбора
                adoMethod.SetParameters(ResContainer.GetMethodCustomParameters(cmbMethodSelectedIndex));
                AnalisysWithStateObject obj = new AnalisysWithStateObject(adoMethod, currentCompression, ref reportInfo);
                //obj.OnProcessDone += OnProcessDoneEventHandler;
                // установить количество экспириментов
                obj.SetNumberofExperiments((double)this.experimentCount.Value);
                Thread thread = new Thread(obj.RunResearchReport);
                // начать анализ
                ShowAdditional();
                thread.Start();
            }
        }
    }
}
